#pragma once 
#include <bits/stdc++.h>


/*****************************************************************************
 *! @brief 使用C++11开发一个轻量级的AOP库
 * 
 * 
 * 
 * 
 *  
 ****************************************************************************/


class NonCopyable {
public:
    // 使用默认无参构造函数
    NonCopyable() = default;

    //! 禁用拷贝构造函数 
    NonCopyable(const NonCopyable& rhs)            = delete;
    
    //! 禁用赋值函数 
    NonCopyable& operator=(const NonCopyable& rhs) = delete;
};

//! std::declval<U>().member(std::declval<Args>()...) 的作用是在不实例化一个U类型对象
//! 的前提下，让decltype可以推断出成员或者成员函数的返回类型.
#define HAS_MEMBER(member)                                                      \
template<typename T, typename... Args>                                          \
struct has_member_##member  {                                                   \
private:                                                                        \
    template<typename U>                                                        \
    static auto check(int) ->                                                   \
        decltype(std::declval<U>().member(std::declval<Args>()...),             \
        std::true_type());                                                      \
                                                                                \
    template<typename U>                                                        \
    static std::false_type check(...);                                          \
public:                                                                         \
    enum {                                                                      \
        value = std::is_same<decltype(check<T>(0)),                             \
                std::true_type>::value                                          \
    };                                                                          \
};

HAS_MEMBER(foo)
HAS_MEMBER(before)
HAS_MEMBER(after)

template<typename Func, typename... Args>                             //! 主函数及参数列表
struct Aspect : NonCopyable {
public:
    Aspect (Func&& f) : _func(std::forward<Func>(f)) { }

    //!  判断类型T有没有对应的Berfore/After方法 + 满足Args...参数的特定方法.
    template<typename T>
    typename std::enable_if<has_member_before<T, Args...>::value && has_member_after<T, Args...>::value>::type  
    invoke(Args&&... args, T&& aspect) {
        aspect.before(std::forward<Args>(args)...);                   // 主逻辑之前注入的切面逻辑
        _func(std::forward<Args>(args)...);                           // 核心主流程的逻辑
        aspect.after(std::forward<Args>(args)...);                    // 主逻辑之后注入的切面逻辑
    }

    //! 只在核心逻辑前注入逻辑
    template<typename T>
	typename std::enable_if<has_member_before<T, Args...>::value && !has_member_after<T, Args...>::value>::type 
    invoke(Args&&... args, T&& aspect) {
		aspect.before(std::forward<Args>(args)...);                   // 核心逻辑之前的切面逻辑
		_func(std::forward<Args>(args)...);                           // 核心逻辑
	}


    //! 只在核心逻辑后注入逻辑
	template<typename T>
	typename std::enable_if<!has_member_before<T, Args...>::value && has_member_after<T, Args...>::value>::type 
    invoke(Args&&... args, T&& aspect) {
		_func(std::forward<Args>(args)...);                          // 核心逻辑
		aspect.after(std::forward<Args>(args)...);                   // 核心逻辑之后的切面逻辑
	}

    //! 原始实现(被注释掉的)必须所有AP都有before/after方法才行
    //! 更细弄得版本可以自由组合
	template<typename Head, typename... Tail>                        // 递归展开
	void invoke(Args&&... args, Head&& headAspect, Tail&&... tailAspect) {
		// headAspect.before(std::forward<Args>(args)...);           // delete
        prefix(std::forward<Args>(args)..., std::forward<Head>(headAspect));
		invoke(std::forward<Args>(args)..., std::forward<Tail>(tailAspect)...);
        suffix(std::forward<Args>(args)..., std::forward<Head>(headAspect));
		// headAspect.after(std::forward<Args>(args)...);            // delete
	}
private:
    template<typename T>
	typename std::enable_if<has_member_before<T, Args...>::value && has_member_after<T, Args...>::value>::type 
    prefix(Args&&... args, T&& aspect) {
        aspect.before(std::forward<Args>(args)...);   
	}

    template<typename T>
	typename std::enable_if<has_member_before<T, Args...>::value && !has_member_after<T, Args...>::value>::type 
    prefix(Args&&... args, T&& aspect) {
		aspect.before(std::forward<Args>(args)...);                  
	}

    template<typename T>
	typename std::enable_if<!has_member_before<T, Args...>::value && has_member_after<T, Args...>::value>::type 
    prefix(Args&&... args, T&& aspect) {
	}


    template<typename T>
	typename std::enable_if<has_member_before<T, Args...>::value && has_member_after<T, Args...>::value>::type 
    suffix(Args&&... args, T&& aspect) {
        aspect.after(std::forward<Args>(args)...);    
	}

    template<typename T>
	typename std::enable_if<has_member_before<T, Args...>::value && !has_member_after<T, Args...>::value>::type 
    suffix(Args&&... args, T&& aspect) {            
	}

    template<typename T>
	typename std::enable_if<!has_member_before<T, Args...>::value && has_member_after<T, Args...>::value>::type 
    suffix(Args&&... args, T&& aspect) {
        aspect.after(std::forward<Args>(args)...);  
	}


private:
    Func _func;                  // 被注入的函数
};


template<typename T>
using identity_t = T;


/**
 * @brief  帮助函数，用于简化对象的创建及成员函数的调用
 * 
 * @tparam AP       切面对象，可能包含有beforez/after等方法
 * @tparam Args     主函数的参数类型列表
 * @tparam Func     主函数类型
 * @param f         主函数名
 * @param args      主函数参数列表
 */
template<typename... AP, typename Func, typename... Args> 
void invoke(Func&& f, Args&&... args) {
    Aspect<Func, Args...> asp(std::forward<Func>(f));                 // 
    asp.invoke(std::forward<Args>(args)..., identity_t<AP>()...);     // identity_t<AP>()...   床架你不同对象, 并使用...展开
}